/**
 * 广寒宫
 * 网址:www.guanghangong.xyz
 */
package org.moon.framework.autoconfigure.secure.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.moon.framework.autoconfigure.MoonConstants;
import org.moon.framework.autoconfigure.cache.CacheService;
import org.moon.framework.autoconfigure.config.SpringContextConfig;
import org.moon.framework.autoconfigure.exception.domain.MoonException;
import org.moon.framework.autoconfigure.secure.AuthUtils;
import org.moon.framework.autoconfigure.secure.annotation.PreAuth;
import org.moon.framework.autoconfigure.utils.ClassUtils;
import org.moon.framework.autoconfigure.utils.Func;

import java.lang.reflect.Method;
import java.util.Set;

/**
 * AOP 鉴权
 * @author moon
 */
@Aspect
@Slf4j
public class AuthAspect{
	
	/**
	 * 切 方法 和 类上的 @PreAuth 注解
	 */
	@Around(
		"@annotation(org.moon.framework.autoconfigure.secure.annotation.PreAuth) || " +
			"@within(org.moon.framework.autoconfigure.secure.annotation.PreAuth)"
	)
	public Object preAuth(ProceedingJoinPoint point) throws Throwable {
		String requestFrom = Func.getRequest().getHeader(MoonConstants.REQUEST_FROM);
		if (Func.isEmpty(requestFrom) || MoonConstants.RequestFormEnum.feign.name().equals(requestFrom) || handleAuth(point)) {
			return point.proceed();
		}
		throw new MoonException(MoonConstants.ACCESS_DENIED);
	}

	/**
	 * 处理权限
	 */
	private boolean handleAuth(ProceedingJoinPoint point) {
		if(AuthUtils.isAdmin()){
			return true;
		}
		MethodSignature ms = (MethodSignature) point.getSignature();
		Method method = ms.getMethod();
		// 读取权限注解，读取方法上
		PreAuth preAuth = ClassUtils.getAnnotation(method, PreAuth.class);
		if(preAuth==null)return true;
		// 判断表达式
		String [] conditions = preAuth.value();
		if (Func.isNotEmpty(conditions)) {
			CacheService cacheService = SpringContextConfig.getBean(CacheService.class);
			Set<String> permissions = cacheService.get(MoonConstants.CACHE_PERMISSION+AuthUtils.getCurrentUserId(),Set.class);
			boolean success = false;
			for(String condition:conditions){
				success = permissions.contains(condition);
				if(success)break;
			}
			if(!success){
				log.error("您没有{}权限,请联系管理员", Func.toArrayStr(conditions));
			}
			return success;
		}
		return false;
	}
}